package han.chensing.latos.game.elements.notes;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import han.chensing.latos.common.level.speed.SpeedFactors;
import han.chensing.latos.common.level.timeLine.TimeLineEventSet;
import han.chensing.latos.res.Res;
import han.chensing.latos.V;
import han.chensing.latos.game.container.FakeShapeRenderer;
import han.chensing.latos.game.elements.LatosElement;
import han.chensing.latos.game.elements.logic.Speed;
import han.chensing.latos.game.util.MathUtil;
import han.chensing.latos.game.util.NoteUtil;

public class Line extends LatosElement {

    protected int num;
    protected List<Note> normalNotes;
    protected List<HoldNote> holdNotes;
    protected Speed speed;
    protected Speed angleSpeed;
    protected Speed noteSpeed;
    protected Speed zAngleSpeed;
    protected float alpha;
    protected float zRotation;
    protected SpeedFactors speedFactors;

    protected int normalJudgeIndex;
    protected int normalDrawIndex;
    protected int holdJudgeIndex;
    protected int holdDrawIndex;

    protected Color lineColor=yellowLineColor;

    protected static final int drawRange=50;
    protected static final int actRange=50;
    protected static final int holdDrawBack=20;
    public static final Color yellowLineColor=Color.valueOf("#fd873a");
    public static final Color blueLineColor=Color.valueOf("#3399ff");
    public static final Color whiteLineColor=new Color(Color.WHITE);

    public Line(int num){
        super(Res.getInstance().get("effectEmpty", TextureRegion.class));
        this.speed=new Speed();
        this.noteSpeed=new Speed();
        this.angleSpeed=new Speed();
        this.zAngleSpeed=new Speed();
        this.normalNotes = Collections.synchronizedList(new ArrayList<>());
        this.holdNotes=Collections.synchronizedList(new ArrayList<>());
        this.normalJudgeIndex =0;
        this.normalDrawIndex =0;
        this.holdDrawIndex=0;
        this.holdJudgeIndex=0;
        this.zRotation=0;
        setColor(new Color(1,1,1,1));
        setRotation(0);
    }

    @Override
    public void lAct(float delta, float currentTime) {
        super.lAct(delta, currentTime);
        if (normalNotes ==null)return;
        speed.updateSpeed(delta);
        noteSpeed.updateSpeed(delta);
        angleSpeed.updateSpeed(delta);
        zAngleSpeed.updateSpeed(delta);
        setX(getX()+speed.getSpeed().x*delta);
        setY(getY()+speed.getSpeed().y*delta);
        setRotation(MathUtil.fixDegree(getRotation()+angleSpeed.getSpeed().x*delta));
        setZRotation(MathUtil.fixDegree(getZRotation()+zAngleSpeed.getSpeed().x*delta));
        float noteSpeed = getNoteSpeed(delta, currentTime);
        int holdLimit=
                Math.min(holdNotes.size(), holdJudgeIndex +actRange);
        for (int i=Math.max(0,holdJudgeIndex-holdDrawBack);i<holdLimit;i++){
            HoldNote holdNote = holdNotes.get(i);
            if (holdNote==null)continue;
            float distanceHeight = (holdNote.getHitTime() - currentTime) * noteSpeed;
            holdNote.setDistanceHeight(distanceHeight);
            holdNote.lAct(delta, currentTime);
        }
    }

    private float getNoteSpeed(float delta, float currentTime) {
        float noteSpeed
                = getNoteSpeed().getSpeed().x;
        int normalLimit=
                Math.min(normalNotes.size(), normalJudgeIndex +actRange);
        for(int i = normalJudgeIndex; i<normalLimit; i++){
            Note note= normalNotes.get(i);
            if (note==null)continue;
            //note.setDistanceHeight((int) (note.getDistanceHeight()-noteSpeed.getSpeed().noteSpeed));
            float distanceHeight = (note.getHitTime() - currentTime) * noteSpeed;
            note.setDistanceHeight(distanceHeight);
            note.lAct(delta, currentTime);
        }
        return noteSpeed;
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        float[] pos1=
                MathUtil.getCrossPointWithScreen(
                        getX(),getY(), MathUtil.fixDegree(getRotation()));
        float[] pos2=
                MathUtil.getCrossPointWithScreen(
                        getX(),getY(), MathUtil.fixDegree(getRotation()+180));
        FakeShapeRenderer ren= V.shapeRenderer;
        assert ren != null;
        //ren.circle(getX(),getY(),7);
        ren.rectLine(pos1[0],pos1[1],pos2[0],pos2[1],5,lineColor,lineColor);
        if (normalNotes ==null)return;
        for(int i = getNormalDrawIndex();
            i<Math.min(normalNotes.size(), getNormalDrawIndex()+drawRange); i++){
            Note note = normalNotes.get(i);
            if (note==null)continue;
            if (!NoteUtil.isInBox(note))continue;
            note.draw(batch, parentAlpha);
        }
        for (int i=Math.max(0,getHoldDrawIndex()-holdDrawBack);
            i<Math.min(holdNotes.size(),getHoldDrawIndex()+drawRange);i++){
            HoldNote holdNote = holdNotes.get(i);
            if (holdNote==null)continue;
            holdNote.draw(batch, parentAlpha);
        }
    }

    public void initSpeedAspects(TimeLineEventSet timeLineEventSet){
        speedFactors.init(timeLineEventSet);
    }

    public List<Note> getNormalNotes() {
        return normalNotes;
    }

    public float getAlpha() {
        return alpha;
    }

    public void setAlpha(float alpha) {
        this.alpha = alpha;
        Color color = getColor();
        this.setColor(color.r, color.g, color.b,alpha);
    }

    public void setNormalNotes(ArrayList<Note> normalNotes) {
        this.normalNotes = normalNotes;
    }

    public Speed getSpeed() {
        return speed;
    }

    public void setSpeed(Speed speed) {
        this.speed = speed;
    }

    public Speed getNoteSpeed() {
        return noteSpeed;
    }

    public void setNoteSpeed(Speed noteSpeed) {
        this.noteSpeed = noteSpeed;
    }

    public int getNormalJudgeIndex() {
        return normalJudgeIndex;
    }

    public void setNormalJudgeIndex(int normalJudgeIndex) {
        this.normalJudgeIndex = normalJudgeIndex;
    }

    public int getNormalDrawIndex() {
        return normalDrawIndex;
    }

    public void setNormalDrawIndex(int normalDrawIndex) {
        this.normalDrawIndex = normalDrawIndex;
    }

    public Speed getAngleSpeed() {
        return angleSpeed;
    }

    public void setAngleSpeed(Speed angleSpeed) {
        this.angleSpeed = angleSpeed;
    }

    public float getZRotation() {
        return zRotation;
    }

    public void setZRotation(float zRotation) {
        this.zRotation = zRotation;
    }

    public Speed getZAngleSpeed() {
        return zAngleSpeed;
    }

    public void setZAngleSpeed(Speed zAngleSpeed) {
        this.zAngleSpeed = zAngleSpeed;
    }

    public List<HoldNote> getHoldNotes() {
        return holdNotes;
    }

    public void setHoldNotes(List<HoldNote> holdNotes) {
        this.holdNotes = holdNotes;
    }

    public int getHoldJudgeIndex() {
        return holdJudgeIndex;
    }

    public void setHoldJudgeIndex(int holdJudgeIndex) {
        this.holdJudgeIndex = holdJudgeIndex;
    }

    public int getHoldDrawIndex() {
        return holdDrawIndex;
    }

    public void setHoldDrawIndex(int holdDrawIndex) {
        this.holdDrawIndex = holdDrawIndex;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public Color getLineColor() {
        return lineColor;
    }

    public void setLineColor(Color lineColor) {
        this.lineColor = lineColor;
    }

    public SpeedFactors getSpeedFactors() {
        return speedFactors;
    }

    public void setSpeedFactors(SpeedFactors speedFactors) {
        this.speedFactors = speedFactors;
    }
}
